import keyword
import re
from types import ModuleType
from typing import Union, Callable

from httprunner import exceptions
from httprunner.parser import Parser
from pydantic import ValidationError

from ._models import TestCaseForBuilder

_used_class_names: set[str] = set()


def safe_class_name(name: str) -> str:
    """将任意字符串转换为唯一且合法的 Python 类名"""
    # 非字母数字替换为下划线
    name = re.sub(r'\W', '_', name)
    # 合并连续下划线
    name = re.sub(r'_+', '_', name).strip('_')
    # 避免数字开头
    if re.match(r'^\d', name):
        name = f"_{name}"
    # 避免关键字冲突
    if keyword.iskeyword(name):
        name = f"{name}_"
    # 转换为驼峰
    parts = name.split('_')
    name = ''.join(word.capitalize() for word in parts if word)
    base_name = f"TestCase{name}" or "TestCaseUnnamed"

    # 避免重名
    unique_name = base_name
    i = 1
    while unique_name in _used_class_names:
        unique_name = f"{base_name}_{i}"
        i += 1

    _used_class_names.add(unique_name)
    return unique_name


def create_debugtalk_parser(m: Union[ModuleType, dict[str, Callable]]) -> Parser:
    if isinstance(m, Parser):
        return m
    if isinstance(m, dict):
        items = m.items()
    elif isinstance(m, ModuleType):
        items = vars(m).items()
    else:
        raise TypeError('m must be one of ModuleType / dict[str, FunctionType] / Parser')

    function_mapping = {}
    for name, item in items:
        if isinstance(item, Callable):
            function_mapping[name] = item
    return Parser(function_mapping)


def validate_case_format(case: dict):
    try:
        TestCaseForBuilder.model_validate(case)
    except ValidationError as ex:
        err_msg = f"TestCase ValidationError:\nerror: {ex}\ncontent: {case}"
        raise exceptions.TestCaseFormatError(err_msg) from ex
